//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V0.0.2
#include "lcd_driver.h"


static WHT_LCD_Info_t WHT_LCD_Info;

static uint16_t LCD_Tx_Buffer[LCD_Buffer_Size];

static WHT_FSMC8080_BSP_t LCD_Driver;

static void WHT_LCD_Driver_Init(void)
{
	WHT_FSMC8080_BSP_Register(&LCD_Driver);
	WHT_LCD_Backlight_Init();
	WHT_LCD_Set_RST(Low);
	WHT_Delay_ms(200);
	WHT_LCD_Set_RST(Hig);
	WHT_LCD_Set_Backlight(5);
}


/**************************控制***********************/
/*读取寄存器*/
static void WHT_LCD_Driver_Get_Reg_Value(uint16_t reg, uint16_t* output_buf,uint32_t count)
{
	LCD_Driver.WHT_Read(reg,output_buf,count);
}
/*设置显示方向*/
static void WHT_LCD_Driver_Set_Display_Mode(WHT_LCD_Display_Mode_enum display_mode)
{
	uint32_t Vertical_Screen_Flag = ~0;//默认竖屏
	uint16_t Reg_Value[2];
	uint16_t Temp;

	switch (display_mode)
	{
	case Display_Mode0:Temp = 0x00; break;
	case Display_Mode1:Temp = 0x20; Vertical_Screen_Flag = 0; break;
	case Display_Mode2:Temp = 0x40; break;
	case Display_Mode3:Temp = 0x60;	Vertical_Screen_Flag = 0; break;
	case Display_Mode4:Temp = 0x80;	break;
	case Display_Mode5:Temp = 0xA0;	Vertical_Screen_Flag = 0; break;
	case Display_Mode6:Temp = 0xC0; break;
	case Display_Mode7:Temp = 0xE0;	Vertical_Screen_Flag = 0; break;
	}
	*(uint16_t*)&WHT_LCD_Info.X_Length = Vertical_Screen_Flag != 0 ? WHT_LCD_Info.Y_Length : WHT_LCD_Info.X_Length;
	*(uint16_t*)&WHT_LCD_Info.Y_Length = Vertical_Screen_Flag != 0 ? WHT_LCD_Info.X_Length : WHT_LCD_Info.Y_Length;;
	LCD_Driver.WHT_Read(0x0B, Reg_Value, 2);
	Temp |= Reg_Value[1] & 0x08;
	LCD_Driver.WHT_Write(0x36, &Temp, 1);
}
/*设置行和行位置*/
static uint8_t WHT_LCD_Driver_Set_Font_Row(uint16_t row, uint16_t pos_x)
{
    uint8_t Max_Display_Font_Row_Number;//屏幕最大显示字体行数
	uint8_t Idle_Row_Number;            //屏幕空闲行数
	
	Max_Display_Font_Row_Number = WHT_LCD_Info.Y_Length / WHT_LCD_Info.Font->Height;
	Idle_Row_Number = WHT_LCD_Info.Y_Length % WHT_LCD_Info.Font->Height;
	WHT_LCD_Info.New_Pos_X = pos_x >= WHT_LCD_Info.X_Length ? 0 : pos_x;
	WHT_LCD_Info.New_Pos_Y = row % Max_Display_Font_Row_Number * WHT_LCD_Info.Font->Height + Idle_Row_Number;//屏幕上方字体空闲区域
	return Idle_Row_Number;
}
/**************************控制***********************/


/************************填充*************************/
static void WHT_LCD_Driver_Set_Window(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey)
{
	uint16_t Window[4];

	Window[0] = sx >> 8;
	Window[1] = sx & 0xff;
	Window[2] = ex >> 8;
	Window[3] = ex & 0xff;
	LCD_Driver.WHT_Write(LCD_Set_Pos_X, Window, 4);//开窗X坐标

	Window[0] = sy >> 8;
	Window[1] = sy & 0xff;
	Window[2] = ey >> 8;
	Window[3] = ey & 0xff;
	LCD_Driver.WHT_Write(LCD_Set_Pos_Y, Window, 4);//开窗Y坐标
}
static void WHT_LCD_Driver_Fill_Buffer(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, const uint16_t* intput_buf)
{
	WHT_LCD_Driver_Set_Window(sx, sy, ex, ey);
	LCD_Driver.WHT_Write(LCD_Fill_Pixel, intput_buf, (ex - sx + 1) * (ey - sy + 1));
}
static void WHT_LCD_Driver_Fill_Color(uint16_t color)
{
	uint32_t Fill_Count;
	uint32_t Page_Count;
	uint32_t End_count;

	Fill_Count = WHT_LCD_Info.X_Length * WHT_LCD_Info.Y_Length;
	Page_Count = Fill_Count / (sizeof(LCD_Tx_Buffer) / 2);
	End_count = Fill_Count & (sizeof(LCD_Tx_Buffer) / 2);
	for (uint32_t i = 0; i < sizeof(LCD_Tx_Buffer) / 2; i++)
		LCD_Tx_Buffer[i] = color;
	/*memcpy memmove只要是自己拷贝自己的均有BUG*/
	//memcpy(LCD_Tx_Buffer+3, LCD_Tx_Buffer, sizeof(LCD_Tx_Buffer) - 2*3);
	
	WHT_LCD_Driver_Set_Window(0, 0, WHT_LCD_Info.X_Length - 1, WHT_LCD_Info.Y_Length - 1);
	LCD_Driver.WHT_Write_Cmd(LCD_Fill_Pixel);
	while (Page_Count--)
	{
		LCD_Driver.WHT_Write_Data(LCD_Tx_Buffer, sizeof(LCD_Tx_Buffer)/2);
	}
	LCD_Driver.WHT_Write_Data(LCD_Tx_Buffer, End_count);
}
/************************填充*************************/


/************************字符*************************/
static void WHT_LCD_Driver_Check_Line_Feed(char intput_char)
{
	if ((intput_char == '\n') || (intput_char == '\r'))
	{
		if (WHT_LCD_Info.New_Pos_Y + WHT_LCD_Info.Font->Height >= WHT_LCD_Info.Y_Length)
			WHT_LCD_Driver_Set_Font_Row(0, 0);//归0
		else
		{
			WHT_LCD_Info.New_Pos_X = 0;
			WHT_LCD_Info.New_Pos_Y += WHT_LCD_Info.Font->Height;
		}
	}
}
static void WHT_LCD_Driver_Puts_ASCII(const char* intput_char)
{
	static uint32_t datax = 0;
	static uint8_t* start_pos = NULL;
	uint32_t row,col;
	
	do
	{
		if( (*intput_char < WHT_LCD_Info.Font->Start_Value) || (*intput_char > WHT_LCD_Info.Font->End_Value) )
		{
			WHT_LCD_Driver_Check_Line_Feed(*intput_char);
			return;
		}
		start_pos = &WHT_LCD_Info.Font->Buffer[(*intput_char - WHT_LCD_Info.Font->Start_Value) * WHT_LCD_Info.Font->Width_Byte * WHT_LCD_Info.Font->Height];//字符位置
		for (row = 0; row < WHT_LCD_Info.Font->Height; row++)
		{
			switch(WHT_LCD_Info.Font->Pixel_Size)
			{
			case  5 *  8:datax = start_pos[row] >> (8 - 5);break;
			case  6 * 12:datax = start_pos[row] >> (8 - 6);break;
			case  8 * 16:datax = start_pos[row] >> (8 - 8);break;
			case 12 * 24:datax = (((uint16_t*)start_pos)[row] >> 8 | ((uint16_t*)start_pos)[row] << 8) >> (16 - 12);break;
			}
			for (col = 0; col < WHT_LCD_Info.Font->Width; col++)
			{
				if( datax & (1 << (WHT_LCD_Info.Font->Width - 1 - col)))
					LCD_Tx_Buffer[row * WHT_LCD_Info.Font->Width + col] = WHT_LCD_Info.Font_Color;//填充前景色颜色
				else
					LCD_Tx_Buffer[row * WHT_LCD_Info.Font->Width + col] = WHT_LCD_Info.BK_Color;  //填充背景色
			}
		}
		if(WHT_LCD_Info.New_Pos_X + WHT_LCD_Info.Font->Width >= WHT_LCD_Info.X_Length)
			WHT_LCD_Driver_Check_Line_Feed('\n');
		WHT_LCD_Driver_Fill_Buffer(WHT_LCD_Info.New_Pos_X, WHT_LCD_Info.New_Pos_Y, WHT_LCD_Info.New_Pos_X + WHT_LCD_Info.Font->Width - 1, WHT_LCD_Info.New_Pos_Y + WHT_LCD_Info.Font->Height - 1, LCD_Tx_Buffer);
		WHT_LCD_Info.New_Pos_X += WHT_LCD_Info.Font->Width;//指针右移1个字符
		intput_char++;
	}while(*intput_char);
}
static void WHT_LCD_Driver_Clear_Row(uint8_t row)
{
	uint32_t Max_Font_Row_Count;
	
	WHT_LCD_Driver_Set_Font_Row(row, 0);                             //设置指针位置
	Max_Font_Row_Count = WHT_LCD_Info.X_Length / WHT_LCD_Info.Font->Width;//获取每行最大显示字体个数
	while (Max_Font_Row_Count--)
	{
		WHT_LCD_Driver_Puts_ASCII(" ");
	}
	WHT_LCD_Driver_Set_Font_Row(WHT_LCD_Info.New_Pos_Y, 0);          //重置指针位置
}
/************************字符*************************/


static void ILI9341_Reg_Config(void)
{
	uint16_t Buffer[15];

	/*  Power control B (CFh)  */
	Buffer[0] = 0x00;
	Buffer[1] = 0x81;
	Buffer[2] = 0x30;
	LCD_Driver.WHT_Write(0xCF, Buffer, 3);
	WHT_Delay_ms(1);

	/*  Power on sequence control (EDh) */
	Buffer[0] = 0x64;
	Buffer[1] = 0x03;
	Buffer[2] = 0x12;
	Buffer[3] = 0x81;
	LCD_Driver.WHT_Write(0xED, Buffer, 4);
	WHT_Delay_ms(1);

	/*  Driver timing control A (E8h) */
	Buffer[0] = 0x85;
	Buffer[1] = 0x10;
	Buffer[2] = 0x78;
	LCD_Driver.WHT_Write(0xE8, Buffer, 3);
	WHT_Delay_ms(1);

	/*  Power control A (CBh) */
	Buffer[0] = 0x39;
	Buffer[1] = 0x2C;
	Buffer[2] = 0x00;
	Buffer[3] = 0x34;
	Buffer[4] = 0x02;
	LCD_Driver.WHT_Write(0xCB, Buffer, 5);
	WHT_Delay_ms(1);

	/* Pump ratio control (F7h) */
	Buffer[0] = 0x20;
	LCD_Driver.WHT_Write(0xF7, Buffer, 1);
	WHT_Delay_ms(1);

	/* Driver timing control B */
	Buffer[0] = 0x00;
	Buffer[1] = 0x00;
	LCD_Driver.WHT_Write(0xEA, Buffer, 2);
	WHT_Delay_ms(1);

	/* Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
	Buffer[0] = 0x00;
	Buffer[1] = 0x1B;
	LCD_Driver.WHT_Write(0xB1, Buffer, 2);
	WHT_Delay_ms(1);

	/*  Display Function Control (B6h) */
	Buffer[0] = 0x0A;
	Buffer[1] = 0xA2;
	LCD_Driver.WHT_Write(0xB6, Buffer, 2);
	WHT_Delay_ms(1);

	/* Power Control 1 (C0h) */
	Buffer[0] = 0x35;
	LCD_Driver.WHT_Write(0xC0, Buffer, 1);
	WHT_Delay_ms(1);

	/* Power Control 2 (C1h) */
	Buffer[0] = 0x11;
	LCD_Driver.WHT_Write(0xC1, Buffer, 1);
	WHT_Delay_ms(1);

	/* VCOM Control 1 (C5h) */
	Buffer[0] = 0x45;
	Buffer[1] = 0x45;
	LCD_Driver.WHT_Write(0xC5, Buffer, 2);
	WHT_Delay_ms(1);

	/*  VCOM Control 2 (C7h)  */
	Buffer[0] = 0xA2;
	LCD_Driver.WHT_Write(0xC7, Buffer, 1);
	WHT_Delay_ms(1);

	/* Enable 3G (F2h) */
	Buffer[0] = 0x00;
	LCD_Driver.WHT_Write(0xF2, Buffer, 1);
	WHT_Delay_ms(1);

	/* Gamma Set (26h) */
	Buffer[0] = 0x01;
	LCD_Driver.WHT_Write(0x26, Buffer, 1);
	WHT_Delay_ms(1);

	/* Positive Gamma Correction */
	Buffer[0] = 0x0F;
	Buffer[1] = 0x26;
	Buffer[2] = 0x24;
	Buffer[3] = 0x0B;
	Buffer[4] = 0x0E;
	Buffer[5] = 0x09;
	Buffer[6] = 0x54;
	Buffer[7] = 0xA8;
	Buffer[8] = 0x46;
	Buffer[9] = 0x0C;
	Buffer[10] = 0x17;
	Buffer[11] = 0x09;
	Buffer[12] = 0x0F;
	Buffer[13] = 0x07;
	Buffer[14] = 0x00;
	LCD_Driver.WHT_Write(0xE0, Buffer, 15);//Set Gamma
	WHT_Delay_ms(1);

	/* Negative Gamma Correction (E1h) */
	Buffer[0] = 0x00;
	Buffer[1] = 0x19;
	Buffer[2] = 0x1B;
	Buffer[3] = 0x04;
	Buffer[4] = 0x10;
	Buffer[5] = 0x07;
	Buffer[6] = 0x2A;
	Buffer[7] = 0x47;
	Buffer[8] = 0x39;
	Buffer[9] = 0x03;
	Buffer[10] = 0x06;
	Buffer[11] = 0x06;
	Buffer[12] = 0x30;
	Buffer[13] = 0x38;
	Buffer[14] = 0x0F;
	LCD_Driver.WHT_Write(0XE1, Buffer, 15);//Set Gamma
	WHT_Delay_ms(1);

	/* memory access control set */
	Buffer[0] = 0xc8;
	LCD_Driver.WHT_Write(0x36, Buffer, 1);/*竖屏  左上角到 (起点)到右下角 (终点)扫描方式*/
	WHT_Delay_ms(1);

	/*  Pixel Format Set (3Ah)  */
	Buffer[0] = 0x55;
	LCD_Driver.WHT_Write(0x3a, Buffer, 1);
	WHT_Delay_ms(1);

	/* Sleep Out (11h)  */
	LCD_Driver.WHT_Write(0x11, Buffer, 0);
	WHT_Delay_ms(200);
	/* Display ON (29h) */
	LCD_Driver.WHT_Write(0x29, Buffer, 0);
	WHT_Delay_ms(50);
}

static void WHT_LCD_Init(void)
{
	*(uint16_t*)&WHT_LCD_Info.X_Length = LCD_SCREEN_Wide;
	*(uint16_t*)&WHT_LCD_Info.Y_Length = LCD_SCREEN_High;
	WHT_LCD_Info.Font = (WHT_Font_Info_t*)&Font_ASCII_8x16;
	WHT_LCD_Info.New_Pos_X = 0;
	WHT_LCD_Info.New_Pos_Y = 0;
	WHT_LCD_Info.BK_Color = RGB565_PURPLE;
	WHT_LCD_Info.Font_Color = RGB565_YELLOW;

	WHT_LCD_Driver_Init();
	ILI9341_Reg_Config();
	WHT_LCD_Driver_Set_Display_Mode(Display_Mode5);
	WHT_LCD_Driver_Fill_Color(WHT_LCD_Info.BK_Color);
	WHT_LCD_Driver_Puts_ASCII("No memcpy memmove func !!!\r\n");
}

const WHT_LCD_Driver_t WHT_LCD_Driver =
{
	.WHT_LCD_Info             = &WHT_LCD_Info,
	.WHT_LCD_Init             = WHT_LCD_Init,
	.WHT_LCD_Get_Reg_Value    = WHT_LCD_Driver_Get_Reg_Value,
	.WHT_LCD_Set_Display_Mode = WHT_LCD_Driver_Set_Display_Mode,
	.WHT_LCD_Set_Font_Row     = WHT_LCD_Driver_Set_Font_Row,
	.WHT_LCD_Fill_Color       = WHT_LCD_Driver_Fill_Buffer,
	.WHT_LCD_Puts             = WHT_LCD_Driver_Puts_ASCII,
	.WHT_LCD_Clear_Row        = WHT_LCD_Driver_Clear_Row,
};
